package cn.hnu.qq.server.thread;

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.JProgressBar;

import org.apache.log4j.Logger;

import cn.hnu.qq.entity.ChartContent;
import cn.hnu.qq.entity.Crowd;
import cn.hnu.qq.entity.TaskEvent;
import cn.hnu.qq.entity.User;
import cn.hnu.qq.entity.message.AddFriendMessage;
import cn.hnu.qq.entity.message.CreateCrowdMessage;
import cn.hnu.qq.entity.message.CrowdInfoMessage;
import cn.hnu.qq.entity.message.DeleteFriendMessage;
import cn.hnu.qq.entity.message.DownLoadFileMessage;
import cn.hnu.qq.entity.message.DownloadMessage;
import cn.hnu.qq.entity.message.ExitCrowdMessage;
import cn.hnu.qq.entity.message.IpInfoMessage;
import cn.hnu.qq.entity.message.JoinCrowdMessage;
import cn.hnu.qq.entity.message.LeaveWordsMessage;
import cn.hnu.qq.entity.message.LogonMessage;
import cn.hnu.qq.entity.message.LogonSuccessMessage;
import cn.hnu.qq.entity.message.Message;
import cn.hnu.qq.entity.message.OnlineMessage;
import cn.hnu.qq.entity.message.QueryCrowdInfoMessage;
import cn.hnu.qq.entity.message.QueryIPInfoMessage;
import cn.hnu.qq.entity.message.RegistMessage;
import cn.hnu.qq.entity.message.ResponseSearchMessage;
import cn.hnu.qq.entity.message.SearchMessage;
import cn.hnu.qq.entity.message.UploadFileMessage;
import cn.hnu.qq.global.FileReceiver;
import cn.hnu.qq.global.FileSender;
import cn.hnu.qq.global.MessageType;

public class ClientServerThread extends AbstractClientThread implements Runnable {

	private User user;
	private boolean flag = true;
	
	public ClientServerThread(Socket s) {
		super(s);
	}

	public void run() {
		System.out.println("进入 ClientServerThread run");
		//TODO 处理input output堵塞
		System.out.println("server run");
				getOutput();//处理input output堵塞
		while(flag ){
			try {
				
				Message message = (Message) getInput().readObject();
				
				System.out.println("获得客户端请求："+message.getMessageType());
				switch(message.getMessageType()){
				case WELCOME:
					Logger.getLogger(this.getClass()).debug("接收服务器发送的欢迎连接消息");
					break;
				case LOGON:
					handleLogon((LogonMessage)message);
					break;
				case QUERY_IP_INFO:
					handleQueryIpInfo((QueryIPInfoMessage) message);
					break;
				case QUERY_CROWD_INFO:
					handleQueryCrowdInfo((QueryCrowdInfoMessage)message);
					break;
				case REGIST:
					handleRegist((RegistMessage) message);
					break;
				case SEARCH_USER:
					handleSearchUser((SearchMessage) message);
					break;
				case SEARCH_CROWD:
					handleSearchCrowd((SearchMessage) message);
					break;
				case ADD_FRIEND:
					handleAddFriend((AddFriendMessage) message);
					break;
				case CONFIRM_ADD_FRIEND:
					handleConfirmAddFriend((AddFriendMessage) message);
					break;
				case JION_CROWD:
					handleJoinCrowd((JoinCrowdMessage) message);
					break;
				case CONFIRM_JOIN_CROWD:
					handleConfirmJoinCrowd((JoinCrowdMessage) message);
					break;
				case LEAVE_WORDS:
					handleLeaveWords((LeaveWordsMessage) message);
					break;
				case DELETE_FRIEND:
					handleDeleteFriend((DeleteFriendMessage) message);
					break;
				case EXIT_CROWD:
					handleExitCrowd((ExitCrowdMessage) message);
					break;
				case CREATE_CROWD:
					handleCreateCrowd((CreateCrowdMessage) message);
					break;
				case UPLOAD_CHART_CONTENT:
					handleUpLoad((ChartContent)message);
					break;
				case DOWNLOAD_CHART_CONTENT:
					handleDownload((DownloadMessage) message);
					break;
				case UPLOAD_FILE:
					handleUploadFile((UploadFileMessage) message);
					break;
				case DOWNLOAD_FILE:
					handleDownloadFile((DownLoadFileMessage) message);
					break;
				}
			} catch (Exception e) {
				if(user != null){
					System.err.println("用户"+user.getAcount()+"退出服务器");
					ListenThread.getInstance().removeClientServerThread(user.getAcount());
					removeOnlineUser(user.getAcount());
					return;
				}
				flag = false;
			}			
		}
	}

	private void handleDownloadFile(DownLoadFileMessage message) throws IOException {
		DownLoadFileMessage dlfm = new DownLoadFileMessage();
		if(message.getSelectedFile() == null || message.getSelectedFile().equals("")){
			File f = new File("E://"+message.getAcount());
			if(!f.exists()){
				f.mkdir();
			}
			File[] files = f.listFiles();
			for(File file:files){
				if(!f.isDirectory()){
					dlfm.addFile(file);
				}
			}
			getOutput().writeObject(dlfm);
			getOutput().flush();
		}else{
			File f = new File(message.getSelectedFile());
			dlfm.setSelectedFile(f.getAbsolutePath());
			FileSender fs = new FileSender(f, message.getAddr(), message.getPort());
			fs.setProgress(new JProgressBar());
			getOutput().writeObject(dlfm);
			getOutput().flush();
			fs.start();
		}
		
	}

	private void handleUploadFile(UploadFileMessage message) throws IOException {
		File f = new File("E://"+message.getUploader());
		if(!f.exists()){
				f.mkdir();
		}
		FileReceiver fr = new FileReceiver("E://"+message.getUploader()+"/");
		int port = 40000;
		while(!fr.bind(port)){
			port++;
		}
		UploadFileMessage ufm = new UploadFileMessage();
		ufm.setPort(port);
		ufm.setFilePath(message.getAbsolutePath());
		getOutput().writeObject(ufm);
		getOutput().flush();
		fr.setProgress(new JProgressBar());
		fr.start();
		
	}

	private void handleDownload(DownloadMessage message) throws IOException {
		User user = getUserDao().findByAcount(message.getUser());
		if(!message.getType()){
			User _user = getUserDao().findByAcount(message.getObj());
			List<ChartContent> charContent = getContentDao().getContent(user, _user);
			DownloadMessage dm = new DownloadMessage();
			dm.setAnswer(charContent);
			dm.setUser(message.getUser());
			dm.setObj(message.getObj());
			dm.setType(message.getType());
			getOutput().writeObject(dm);
			getOutput().flush();
		}else{
			Crowd crowd = getCrowdDao().findByName(message.getObj());
			List<ChartContent> charContent = getContentDao().getContent(user, crowd);
			DownloadMessage dm = new DownloadMessage();
			dm.setAnswer(charContent);
			dm.setUser(message.getUser());
			dm.setObj(message.getObj());
			dm.setType(message.getType());
			getOutput().writeObject(dm);
			getOutput().flush();
		}
	}

	private void handleUpLoad(ChartContent message) throws IOException {
		getContentDao().merge(message);
		Message mes = new Message(MessageType.SUCCESS_UPLOAD);
		getOutput().writeObject(mes);
		getOutput().flush();
	}

	private void handleCreateCrowd(CreateCrowdMessage message) throws IOException {
		Crowd crowd = getCrowdDao().findByName(message.getCrowdName());
		if(crowd != null){
			Message mess = new Message(MessageType.CROWD_EXIT);
			getOutput().writeObject(mess);
			getOutput().flush();
		}else{
			crowd = new Crowd();
			crowd.setCrowdName(message.getCrowdName());
			User u = getUserDao().findByAcount(message.getUser());
			crowd.setCreater(u);
			crowd.addUser(u);
			getCrowdDao().merge(crowd);
			message.setMessageType(MessageType.SUCCESS_CREATE_CROWD);
			getOutput().writeObject(message);
			getOutput().flush();
		}
		
	}

	private void handleExitCrowd(ExitCrowdMessage message) throws IOException {
		getCrowdDao().exitCrowd(message.getCrowd(),message.getUser());
		Crowd crowd = getCrowdDao().findByName(message.getCrowd());
		Map<String,User> users = new HashMap<String,User>();
		Set<User> _users = crowd.getUsers();
		for(User u :_users){
			if(userinfos.get(u.getAcount()) != null){
				User _user = userinfos.get(u.getAcount());
				users.put(_user.getAcount(), _user);
			}
		}
		CrowdInfoMessage cim = new CrowdInfoMessage();
		cim.setUsers(users);
		cim.setCrowd(crowd);
		for(User u:_users){
			if(isUserOnline(u.getAcount()) != null){
				ClientServerThread cst = ListenThread.getInstance().getClientServerThread(u.getAcount());
				if(cst!=null){
					cst.getOutput().writeObject(cim);
					cst.getOutput().flush();
				}
			}
		}
		getOutput().writeObject(message);
		getOutput().flush();
	}

	private void handleDeleteFriend(DeleteFriendMessage message) throws IOException {
		getUserDao().deleteFriend(message.getUser(),message.getFriend());
		if(isUserOnline(message.getFriend()) != null){
			ClientServerThread cst = ListenThread.getInstance().getClientServerThread(message.getFriend());
			if(cst != null){
				cst.getOutput().writeObject(message);
				cst.getOutput().flush();
			}
		}
		getOutput().writeObject(message);
		getOutput().flush();
	}

	private void handleLeaveWords(LeaveWordsMessage message) {
		TaskEvent task = new TaskEvent(MessageType.LEAVE_WORDS);
		User lUser = getUserDao().findByAcount(message.getLeaver());
		User sUser = getUserDao().findByAcount(message.getScanner());
		if(lUser == null || sUser == null){
			return;
		}
		task.setDealer(sUser);
		task.setMaker(lUser);
		task.setSource(message.getLeavingWords());
		task.setTime(new Date());
		getTaskEventDao().persist(task);
	}

	private void handleConfirmJoinCrowd(JoinCrowdMessage message) throws IOException {
		int result = getCrowdDao().joinCrowd(message.getUser(), message.getCrowd());
		JoinCrowdMessage mess = null;
		ClientServerThread cst = ListenThread.getInstance().getClientServerThread(message.getUser());
		if(cst != null){
			
		
		if(result == 0){
			mess = new JoinCrowdMessage(MessageType.CONFIRM_JOIN_CROWD);
			mess.setCrowd(message.getCrowd());
			mess.setUser(message.getUser());
			cst.getOutput().writeObject(mess);
			cst.getOutput().flush();
		}else{
			mess = new JoinCrowdMessage(MessageType.ERROR);
			cst.getOutput().writeObject(mess);
			getOutput().flush();
			return;
		}
		}
		Crowd crowd = getCrowdDao().findByName(message.getCrowd());
		Set<User> members  = crowd.getUsers();
		Map<String,User> users = new HashMap<String,User>();
		for(User uu :members){
			if(userinfos.get(uu.getAcount()) != null){
				User _user = userinfos.get(uu.getAcount());
				users.put(_user.getAcount(), _user);
			}
		}
		for(User u:members){
			ClientServerThread _cst = ListenThread.getInstance().getClientServerThread(u.getAcount());
			//如果该用户在线
			if(_cst != null){
				CrowdInfoMessage cim = new CrowdInfoMessage();
				cim.setUsers(users);
				cim.setCrowd(crowd);
				_cst.getOutput().writeObject(cim);
				_cst.getOutput().flush();
			}
		}
	}

	private void handleJoinCrowd(JoinCrowdMessage message) throws IOException{
		TaskEvent task = new TaskEvent(MessageType.JION_CROWD);
		Crowd crowd = getCrowdDao().findByName(message.getCrowd());
		task.setMaker(getUserDao().findByAcount(message.getUser()));
		task.setDealer(crowd.getCreater());
		task.setSource(message.getCrowd());
		task.setTime(new Date());
		if(getCrowdDao().isAlreadyInCrowd(message.getUser(),message.getCrowd())){
			Message mess = new Message(MessageType.ALREADY_IN_CROWD);
			getOutput().writeObject(mess);
			getOutput().flush();
			return;
		}
		if(isUserOnline(crowd.getCreater().getAcount()) != null){
			//在线
			ClientServerThread cst = ListenThread.getInstance().getClientServerThread(crowd.getCreater().getAcount());
			cst.getOutput().writeObject(task);
			cst.getOutput().flush();
			return;
		}
		getTaskEventDao().persist(task);
		
	}

	private void handleConfirmAddFriend(AddFriendMessage message) throws IOException {
		getUserDao().addFriend(message.getUser(), message.getFriend());		
		ClientServerThread cst = ListenThread.getInstance().getClientServerThread(message.getUser());
		if(cst != null){
			AddFriendMessage mes = new AddFriendMessage(MessageType.CONFIRM_ADD_FRIEND);
			mes.setFriend(message.getFriend());
			mes.setUser(message.getUser());
			cst.getOutput().writeObject(mes);
			cst.getOutput().flush();
		}
	}

	private void handleAddFriend(AddFriendMessage message) throws IOException{
		User user = getUserDao().findByAcount(message.getUser());
		User friend = getUserDao().findByAcount(message.getFriend());
		TaskEvent task = new TaskEvent(MessageType.ADD_FRIEND);
		task.setDealer(friend);
		task.setMaker(user);
		task.setTime(new Date());
		if(getUserDao().isFriend(user.getAcount(),friend.getAcount())){
			Message mess = new Message();
			mess.setMessageType(MessageType.FRIEND_EXIT);
			getOutput().writeObject(mess);
			getOutput().flush();
			return;
		}
		if(isUserOnline(friend.getAcount()) != null){
			ClientServerThread cst = ListenThread.getInstance().getClientServerThread(friend.getAcount());
			cst.getOutput().writeObject(task);
			cst.getOutput().flush();
			return;
		}
		
		getTaskEventDao().persist(task);
		
	}

	private void handleSearchCrowd(SearchMessage message) throws IOException {
		Crowd crowd = getCrowdDao().findByName((message.getInfo()));
		ResponseSearchMessage esm = new ResponseSearchMessage(MessageType.SEARCH_CROWD);
		esm.setScource(crowd);
		getOutput().writeObject(esm);
		getOutput().flush();
		
	}

	private void handleSearchUser(SearchMessage message) throws IOException {
		User user = getUserDao().findByAcount(message.getInfo());
		ResponseSearchMessage esm = new ResponseSearchMessage(MessageType.SEARCH_USER);
		esm.setScource(user);
		getOutput().writeObject(esm);
		getOutput().flush();
	}

	private void handleRegist(RegistMessage message) throws IOException {
		User user = message.getUser();
		User _user = getUserDao().findByAcount(user.getAcount());
		if(_user != null){
			Message mes = new Message();
			mes.setMessageType(MessageType.ACCOUNT_EXIST);
			getOutput().writeObject(mes);
			getOutput().flush();
			return;
		}
		getUserDao().save(user);
		Message mes = new Message();
		mes.setMessageType(MessageType.REGIST_SUCCESS);
		getOutput().writeObject(mes);
		getOutput().flush();
		
	}

	private void handleQueryCrowdInfo(QueryCrowdInfoMessage message) throws Exception {
		String crowdName = message.getCrowdName();
		Crowd crowd = getCrowdDao().findByName(crowdName);
		Map<String,User> users = new HashMap<String,User>();
		Set<User> _users = crowd.getUsers();
		for(User u :_users){
			if(userinfos.get(u.getAcount()) != null){
				User _user = userinfos.get(u.getAcount());
				users.put(_user.getAcount(), _user);
			}
		}
		CrowdInfoMessage cim = new CrowdInfoMessage();
		cim.setUsers(users);
		cim.setCrowd(crowd);
		getOutput().writeObject(cim);
		getOutput().flush();
	}

	private void handleQueryIpInfo(QueryIPInfoMessage message) throws Exception {
		String account = message.getAccount();
		User user = null;
		if((user = isUserOnline(account)) == null){
			//TODO 处理用户不在线的情况
			IpInfoMessage mes = new IpInfoMessage(MessageType.USER_NOT_ONLINE);
			mes.setAccount(account);
			getOutput().writeObject(mes);
			getOutput().flush();
		}else{
			IpInfoMessage mes = new IpInfoMessage();
			mes.setAccount(account);
			mes.setIpAddr(user.getIp());
			mes.setClientListenPort(userinfos.get(account).getUserClientPort());
			getOutput().writeObject(mes);
			getOutput().flush();
		}
		
	}

	private void handleLogon(LogonMessage message) throws Exception {
		User user = getUserDao().findByAcount(message.getUserName());
		if(user == null){
			Message mess = new Message(MessageType.ACCOUNT_NOT_FOUND);
			getOutput().writeObject(mess);
			getOutput().flush();
			return;
		}
		if(user.getPassword().equals(message.getPassword())){
			LogonSuccessMessage ms = new LogonSuccessMessage();
			user.setUserClientPort(message.getClientListenPort()); //设置客户端监听端口
			//TODO  通知在线好友 我上线啦
			Set<User> users = user.getFriends();
			for(User u:users){
				User _user = isUserOnline(u.getAcount());
				if(_user != null){
					//告知该地址用户 我上线啦
					OnlineMessage om = new OnlineMessage();
					om.setAccount(user.getAcount());
					om.setIpAddr(getSocket().getInetAddress().getHostAddress());
					om.setPort(message.getClientListenPort());
					ClientServerThread cst = ListenThread.getInstance().getClientServerThread(_user.getAcount());
					if(cst != null){
						System.err.println("发送在线消息");
						cst.sendOnlineMessage(om);
					}
					u.setIp(_user.getIp());
					u.setUserClientPort(_user.getUserClientPort());
				}
				
			}
			user.setIp(getSocket().getInetAddress().getHostAddress());
			ms.setUser(user);
			System.out.println(user);
			userinfos.put(user.getAcount(), user);
			getOutput().writeObject(ms);
			getOutput().flush();
			ListenThread.getInstance().petClientServerThread(user.getAcount(),this);
			
			//TODO 查找任务发送出去
			List<TaskEvent> tasks = getTaskEventDao().ComplementTask(user);
			handleTasks(tasks);
			this.user = user;
		}else{
			Message mess = new Message(MessageType.PASSWORD_FALSE);
			getOutput().writeObject(mess);
			getOutput().flush();
		}
	}

	private void handleTasks(List<TaskEvent> tasks) throws IOException {
		for(TaskEvent task:tasks){
			getOutput().writeObject(task);
			getOutput().flush();
		}
		
	}

	private void sendOnlineMessage(OnlineMessage om) throws Exception {
		getOutput().writeObject(om);
		getOutput().flush();
	}
	
	
}
